package com.hzqy.commons.utils;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.joda.time.DateTime;
import org.joda.time.Instant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.lang.reflect.Field;
import java.net.*;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Pattern;

public class WChatPayUtil {

	protected static final Logger LOG = LoggerFactory.getLogger(WChatPayUtil.class);

	public static final String CHARSET = "UTF-8";
	public static final String appid = "wxaaeb740f8304ad40";//公众帐号appid
	public static final String mch_id = "1373221902";//商户号
	public static final String tt = "IkLtmAWwaFjxapb2U0VsPcdBEJpluIgI";//商户帐号API秘钥
	public static final File cert = new File("/home/apache-tomcat-8.5.54/webapps/web/WEB-INF/classes/com/hzqy/service/wchatapiclient_cert.p12");

	public static final long time_expire = 10 * 60 * 1000;//超时时间 10分钟后
	public static final Pattern TRADE_NO_PATTERN = Pattern.compile("[0-9]{1,32}");
	public static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	//private static final Random RANDOM = new Random();
	private static final SecureRandom RANDOM = new SecureRandom();


	/**
	 * 获取微信日期格式字符串
	 */
	private static final DateFormat WCHAT_DATE_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss");
	public static final String format(Date date) {
		long time = date.getTime();
		DateTime dateTime = new DateTime(time);
		return dateTime.toString("yyyyMMddHHmmss");
		//return WCHAT_DATE_FORMAT.format(date);
	}

	/**
	 * 生成商户订单号
	 */
	public static final String createOrderId() {
		return String.format("%s%s", System.currentTimeMillis(), randomNumber(6));
	}

	/**
	 * 生成商户退款单号
	 */
	public static final String createRefundNo(){
		return String.format("NO.HZKD%sTK%s", System.currentTimeMillis(), randomNumber(6));
	}

	public static void main(String[] args) {
		System.out.println(randomString(32));
	}

	/**
	 * 生成length长度的字符串
	 */
	private static final char[] ALL_CHAR = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
	public static final String randomString(int length) {
		return randomString(ALL_CHAR, length);
	}
	public static final String randomString(char[] charArr,int length) {
		StringBuffer str = new StringBuffer(length);
		for (int i = 0; i < length; i++) {
			str.append(charArr[RANDOM.nextInt(charArr.length)]);
		}
		return str.toString();
	}
	private static final char[] NUM_CHAR = "0123456789".toCharArray();
	public static final String randomNumber(int length){
		return randomString(NUM_CHAR, length);
	}

	/**
	 * 生成sign签名
	 */
	public static final String sign(Map<String, Object> map, String key) {
		StringBuffer str = new StringBuffer();
		Locale.setDefault(Locale.ENGLISH);
		if(map instanceof SortedMap){
			for(Entry<String, Object> entry : map.entrySet()){
				String value = String.valueOf(entry.getValue());
				if(StringUtils.isNotEmpty(value)){
					str.append(entry.getKey()).append("=").append(value).append("&");
				}
			}
		}else{
			Object[] keyArr = map.keySet().toArray();
			Arrays.sort(keyArr);
			for (Object obj : keyArr) {
				String value = String.valueOf(map.get(obj));
				if(StringUtils.isNotEmpty(value)){
					str.append(String.valueOf(obj)).append("=").append(value).append("&");
				}
			}
		}

		str.append("key=").append(key);
		String sign = MD5Util.MD5Encode(str.toString(), CHARSET).toUpperCase();
		LOG.debug(str.toString() + " -> " + sign);
		return sign;
	}

	/**
	 * 验证map中的sign签名
	 */
	public static final boolean checkSign(Map<String, Object> map, String sign, String key){
		if(StringUtils.isNotEmpty(sign) && !"null".equals(sign)){
			String correctSign = sign(map, key);
			if(correctSign.equals(sign)){
				return true;
			}else{
				LOG.debug("sing检查失败: 预期值=" + correctSign + " 传入值=" + sign);
			}
		}else{
			LOG.debug("map中没有sign签名!");
			return false;
		}
		return false;
	}

	/**
	 * @param type 1、 1个月 2、 24小时
	 */
	public static final String getOrderEndDate(int type){
		Calendar c = Calendar.getInstance();
		if(type == 1){
			c.add(Calendar.DAY_OF_YEAR, 30);
		}else if(type == 2){
			c.add(Calendar.DAY_OF_YEAR, 1);
		}
		Date date = c.getTime();
		long time = date.getTime();
		DateTime dateTime = new DateTime(time);
		return dateTime.toString("yyyy-MM-dd HH:mm:ss");
		//return DATE_FORMAT.format(c.getTime());
	}

	public static final boolean checkDateRange(String start, String end, String dest){
		Instant startDate = Instant.parse(start);
		Instant endDate = Instant.parse(end);
		Instant destDate = Instant.parse(dest);

		if(startDate.compareTo(destDate)<0&& endDate.compareTo(destDate)>0){
			return true;
		}
		return false;
	}

	public static final String getSecretCode(String source){
		return SystemConfigUtils.getSysConfig("secret.secretcode." + source);
	}



	/**
	 * map转成对应Object 忽略不存在的属性
	 */
	public static final <T> T mapToObj(Map<String, Object> map, Class<T> cls){
		try {
			T t = cls.newInstance();
			Iterator<Entry<String, Object>> it = map.entrySet().iterator();
			while(it.hasNext()){
				Entry<String, Object> e = it.next();
				try {
					Field field = cls.getDeclaredField(e.getKey());
					String type = field.getGenericType().toString();
					String value = String.valueOf(e.getValue());
					/*field.setAccessible(true);*/
					org.springframework.util.ReflectionUtils.makeAccessible(field);
					if("class java.lang.Integer".equals(type) || "int".equals(type)){
						field.set(t, Integer.valueOf(value));
					}else{
						field.set(t, value);
					}
				} catch (NoSuchFieldException e1) {
					continue;
				}
			}
			return t;
		} catch (Exception e) {
			LOG.error("mapToObj ", e);
		}
		return null;
	}

	/**
	 *
	 * payment -> map
	 *
	 */
	public static final Map<String, Object> paymentToMap(Object obj){
		Map<String, Object> map = new HashMap<String, Object>();
		Field[] fields = obj.getClass().getDeclaredFields();
		for(Field field : fields){
			try {
				field.setAccessible(true);
				String name = field.getName();
				Object value = field.get(obj);

				if("paytype".equals(name) ||
						"serverid".equals(name) ||
						"resolution".equals(name) ||
						"product_id".equals(name) ||
						"back_url".equals(name) ||
						"notify_url".equals(name) ||
						"group".equals(name) ||
						"trade_no".equals(name) ||
						"source".equals(name) ||
						"timestamp".equals(name) ||
						"sign".equals(name)
				){
					map.put(field.getName(), String.valueOf(value));
				}
			} catch (Exception e) {
				LOG.error("", e);
			}
		}
		return map;
	}


	/**
	 *
	 * obj -> map
	 *
	 */
	public static final Map<String, Object> objToMap(Object obj){
		Map<String, Object> map = new HashMap<String, Object>();
		Field[] fields = obj.getClass().getDeclaredFields();
		for(Field field : fields){
			try {
				field.setAccessible(true);
				Object value = field.get(obj);
				if(value != null){
					map.put(field.getName(), String.valueOf(value));
				}
			} catch (Exception e) {
				LOG.error("", e);
			}
		}
		return map;
	}


	/**
	 * 获取InputStream中的文本
	 */
	public static final String getStringFromInputStream(InputStream in){
		StringBuffer str = new StringBuffer();
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new InputStreamReader(in, CHARSET));
			String temp = null;
			while((temp = reader.readLine()) != null){
				str.append(temp);
			}
		} catch (IOException e1) {
			LOG.error("IOException ", e1);
		}finally{
			try {
				if(reader != null) reader.close();
				if(in != null) in.close();
			} catch (IOException e) {
				LOG.error("IOException ", e);
			}
		}
		return str.toString();
	}

	/**
	 * 将文本写到Writer中
	 */
	public static final void printToWriter(Writer writer, String text){
		try {
			writer.write(text);
			writer.flush();
		} catch (IOException e) {
			LOG.error("IOException", e);
		} finally {
			close(writer);
		}
	}


	public static Map<String, String> post(String urlStr, String text) {
		OutputStream writer = null;
		HttpURLConnection httpConn = null;
		Map<String, String> result = new HashMap<String, String>();
		String msg = "";
		String success = "0";
		InputStream is = null;
		try {// 获取HttpURLConnection连接对象
			URL url = new URL(urlStr);
			httpConn = (HttpURLConnection) url.openConnection();
			// 设置连接属性
			httpConn.setConnectTimeout(20000);
			httpConn.setReadTimeout(30000);
			httpConn.setDoInput(true);
			httpConn.setDoOutput(true);
			httpConn.setUseCaches(false);
			httpConn.setRequestProperty("Connection", "Keep-Alive");
			httpConn.setRequestProperty("Charset", CHARSET);
			httpConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
			httpConn.setRequestMethod("POST");

			writer = httpConn.getOutputStream();
			writer.write(text.getBytes(CHARSET));
			writer.flush();
			is = httpConn.getInputStream();
			int respCode = httpConn.getResponseCode();
			if (respCode == 200) {
				success = "1";
				msg = getStringFromInputStream(is);
			}else{
				success = "2";
				msg = "response_status: " + respCode;
			}
		} catch (Exception e) {
			success = "2";
			//msg = e.getMessage();
		}finally {
			if(httpConn != null)
				httpConn.disconnect();
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
				}
			}
			close(writer);

		}


		result.put("msg", msg);
		result.put("success", success);
		return result;
	}


	/**
	 * 带安全证书的post请求
	 */
	public static final String postSSL(String url, String text, File cert, String mch_id){
		StringBuffer str = new StringBuffer();
		CloseableHttpClient httpclient = null;
		CloseableHttpResponse response = null;
		FileInputStream in = null;
		try {
			KeyStore keyStore = KeyStore.getInstance("PKCS12");
			in = new FileInputStream(cert);
			keyStore.load(in, mch_id.toCharArray());
			in.close();
			SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mch_id.toCharArray()).build();
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext);
			httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
			HttpPost httpPost = new HttpPost(url);
			StringEntity reqEntity  = new StringEntity(text);
			reqEntity.setContentType("application/x-www-form-urlencoded");
			httpPost.setEntity(reqEntity);
			response = httpclient.execute(httpPost);
			HttpEntity entity = response.getEntity();
			if (entity != null) {
				BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(), CHARSET));
				String line = null;
				while ((line = bufferedReader.readLine()) != null) {
					str.append(line);
				}
			}
			EntityUtils.consume(entity);
		} catch (Exception e) {
			LOG.error("postSSL ", e);
		} finally {
			close(httpclient);
			close(response);
			close(in);
		}
		return str.toString();
	}


	/**
	 * 获取本机网络ip
	 */
	public static final String localIp() {
		/*try {
			Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface
					.getNetworkInterfaces();
			while (allNetInterfaces.hasMoreElements()) {
				NetworkInterface networkInterface = allNetInterfaces
						.nextElement();
				List<InterfaceAddress> interfaceAddress = networkInterface
						.getInterfaceAddresses();
				for (InterfaceAddress ia : interfaceAddress) {
					InetAddress ip = ia.getAddress();
					if (ip != null
							&& ip instanceof Inet4Address
							&& !ip.isLoopbackAddress()
							&& !ip.isSiteLocalAddress()
							&& ip.getHostAddress().indexOf(":") == -1) {
						return ip.getHostAddress();
					}
				}
			}
		} catch (SocketException e) {
			LOG.error("SocketException", e);
		}*/
		return null;
	}

	private static final void close(Closeable c){
		if(c != null){
			try {
				c.close();
			} catch (IOException e) {
				LOG.error("IOException", e);
			}
		}
	}




}
